package com.guazai.project.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.guazai.common.pojo.InterfaceInfo;
import com.guazai.common.pojo.InterfaceLogWeekCount;
import com.guazai.common.pojo.User;
import com.guazai.common.pojo.UserInterfaceInfo;
import com.guazai.project.common.ErrorCode;
import com.guazai.project.exception.BusinessException;
import com.guazai.project.mapper.InterfaceInfoMapper;
import com.guazai.project.model.dto.interfaceinfo.InterfaceInfoInvokeRequest;
import com.guazai.project.model.dto.interfaceinfo.InterfaceInfoQueryRequest;
import com.guazai.project.model.enums.InterfaceInfoStatusEnum;
import com.guazai.project.model.vo.AnalysisVO;
import com.guazai.project.model.vo.InterfaceInfoTotalCountVO;
import com.guazai.project.model.vo.InterfaceInfoVO;
import com.guazai.project.model.vo.TopInterfaceInfoVO;
import com.guazai.project.service.InterfaceInfoService;
import com.guazai.project.service.InterfaceLogWeekCountService;
import com.guazai.project.service.UserInterfaceInfoService;
import com.guazai.project.service.UserService;
import com.qiteng.apiclientsdk.client.ApiClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.guazai.project.constant.RedisConstant.INTERFACE_LEFT_NUM;

/**
 * @author guazai
 * @description 针对表【interface_info(接口信息)】的数据库操作Service实现
 * @createDate 2024-07-14 00:01:01
 */
@Service
@Slf4j
public class InterfaceInfoServiceImpl extends ServiceImpl<InterfaceInfoMapper, InterfaceInfo>
        implements InterfaceInfoService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    UserService userService;

    @Resource
    InterfaceInfoMapper interfaceInfoMapper;

    @Resource
    InterfaceLogWeekCountService interfaceLogWeekCountService;

    @Resource
    UserInterfaceInfoService userInterfaceInfoService;

    /**
     * 判断interfaceInfo信息是否合理
     *
     * @param interfaceInfo
     * @param add
     */
    @Override
    public void validInterfaceInfo(InterfaceInfo interfaceInfo, boolean add) {
        if (interfaceInfo == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String name = interfaceInfo.getName();
        // 创建时，所有参数必须非空
        if (add) {
            if (StringUtils.isAnyBlank(name)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
        }
        if (StringUtils.isNotBlank(name) && name.length() > 50) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "名称过长");
        }
    }

    /**
     * 调用接口
     *
     * @param invokeRequest
     * @param request
     * @return
     */
    @Override
    public String invokeInterfaceInfo(InterfaceInfoInvokeRequest invokeRequest, HttpServletRequest request) {
        long id = invokeRequest.getId();
        // 请求的模拟接口是否存在，状态是否可用，以及请求方法是否匹配
        InterfaceInfo oldInterfaceInfo = this.getById(id);
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        if (oldInterfaceInfo.getStatus() == InterfaceInfoStatusEnum.OFFLINE.getValue()) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "接口已关闭");
        }
        // 调用接口
        User loginUser = userService.getLoginUser(request);
        String accessKey = loginUser.getAccessKey();
        String secretKey = loginUser.getSecretKey();
        ApiClient tempClient = new ApiClient(accessKey, secretKey);
        Map<String, Object> requestMap = invokeRequest.getRequestParams();
        Gson gson = new Gson();
        String params = gson.toJson(requestMap);
        String resultJson = tempClient.invokeInterface(params, oldInterfaceInfo.getPath(), oldInterfaceInfo.getMethod());
        // 如果result为空，可能是传入的参数为空
        if (StringUtils.isBlank(resultJson)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "参数输入错误或调用失败");
        }
        return resultJson;
    }

    /**
     * 查询使用次数排名前三的接口
     *
     * @return
     */
    @Override
    public List<AnalysisVO> getTopInterfaceInfo() {
        return interfaceInfoMapper.getTopInterfaceInfo(3);
    }

    /**
     * 分页查询InterfaceInfoVO
     *
     * @param request
     * @return
     */
    @Override
    public Page<InterfaceInfoVO> listInterfaceInfoVOByPage(InterfaceInfoQueryRequest request) {
        //分页查询条件封装
        Page<InterfaceInfo> page = new Page<>(request.getCurrent(), request.getPageSize());
        QueryWrapper<InterfaceInfo> wrapper = new QueryWrapper<>();
        String name = request.getName();
        String description = request.getDescription();
        String path = request.getPath();
        String method = request.getMethod();
        Integer status = request.getStatus();
        wrapper.like(StringUtils.isNotBlank(name),"name", name);
        wrapper.like(StringUtils.isNotBlank(description),"description", description);
        wrapper.like(StringUtils.isNotBlank(path),"path", path);
        wrapper.eq(StringUtils.isNotBlank(method),"method", method);
        wrapper.eq(status != null, "status", status);
        //查询
        interfaceInfoMapper.selectPage(page, wrapper);
        List<InterfaceInfo> records = page.getRecords();
        //如果查询结果为空，则返回一个空记录的Page<UserVO>
        Page<InterfaceInfoVO> interfaceInfoVOPage = new Page<>();
        if (CollectionUtils.isEmpty(records)) {
            interfaceInfoVOPage.setRecords(new ArrayList<>());
            return interfaceInfoVOPage;
        }
        //把结果映射成UserVO
        List<InterfaceInfoVO> result = records.stream().map(this::getInterfaceInfoVO).collect(Collectors.toList());
        interfaceInfoVOPage.setRecords(result);
        return interfaceInfoVOPage;
    }

    /**
     * 获得接口总调用次数
     * @return
     */
    @Override
    public Long getInterfaceInfoTotalInvokesCount() {
        Integer count = interfaceInfoMapper.getInterfaceInfoTotalInvokesCount();
        if (count == null) {
            count = 0;
        }
        return count.longValue();
    }

    /**
     * 获得热门接口信息和最热门接口
     * @return
     */
    @Override
    public TopInterfaceInfoVO getTop() {
        //获得接口调用数（一周）
        List<InterfaceLogWeekCount> weekCountList = interfaceLogWeekCountService.list();
        //接口调用排行（）
        QueryWrapper<InterfaceInfo> wrapper = new QueryWrapper<>();
        wrapper.orderBy(true, false, "totalInvokes");
        List<InterfaceInfo> interfaceInfos = this.list(wrapper);
        List<InterfaceInfoTotalCountVO> rankList = interfaceInfos.stream().map(interfaceInfo -> BeanUtil.copyProperties(interfaceInfo, InterfaceInfoTotalCountVO.class)).collect(Collectors.toList());
        TopInterfaceInfoVO topVO = new TopInterfaceInfoVO();
        //获得最受欢迎接口名字
        String mostPopular = rankList.get(0).getName();
        if (mostPopular == null) {
            mostPopular = "";
        }
        //设置topVO
        topVO.setInterfaceLogWeekCounts(weekCountList);
        topVO.setInterfaceInfoTotalCount(rankList);
        topVO.setMostPopular(mostPopular);
        return topVO;
    }

    /**
     * 将interfaceInfo转换成interfaceInfoVO
     *
     * @param interfaceInfo
     * @return
     */
    public InterfaceInfoVO getInterfaceInfoVO(InterfaceInfo interfaceInfo) {
        if (interfaceInfo == null) {
            return null;
        }

        InterfaceInfoVO interfaceInfoVO = new InterfaceInfoVO();
        BeanUtils.copyProperties(interfaceInfo, interfaceInfoVO);
        interfaceInfoVO.setUrl(interfaceInfo.getPath());
        return interfaceInfoVO;
    }

    /**
     * 将数据库中用户的剩余调用次数加载进redis中
     */
    @Override
    public void loadInRedis() {
        List<UserInterfaceInfo> userInterfaceInfoList = userInterfaceInfoService.list();
        for (UserInterfaceInfo userInterfaceInfo : userInterfaceInfoList) {
            stringRedisTemplate.opsForValue().set(INTERFACE_LEFT_NUM + userInterfaceInfo.getUserId() + ":"
                    + userInterfaceInfo.getInterfaceId(), String.valueOf(userInterfaceInfo.getLeftNum()));
        }
    }
}




